package io.renren.modules.yckj.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.faceid.v20180301.FaceidClient;
import com.tencentcloudapi.faceid.v20180301.models.IdCardVerificationRequest;
import com.tencentcloudapi.faceid.v20180301.models.IdCardVerificationResponse;
import io.renren.common.exception.ErrorCode;
import io.renren.common.page.PageData;
import io.renren.common.service.impl.CrudServiceImpl;
import io.renren.common.validator.AssertUtils;
import io.renren.modules.yckj.common.ThreadLocalUtil;
import io.renren.modules.yckj.common.wx.HttpClientUtil;
import io.renren.modules.yckj.common.wx.WeChatProperties;
import io.renren.modules.yckj.dao.UserDao;
import io.renren.modules.yckj.dto.CouponsLogsDTO;
import io.renren.modules.yckj.dto.TeamDTO;
import io.renren.modules.yckj.dto.UserDTO;
import io.renren.modules.yckj.dto.api.LoginDTO;
import io.renren.modules.yckj.entity.TeamRelationEntity;
import io.renren.modules.yckj.entity.TokenEntity;
import io.renren.modules.yckj.entity.UserEntity;
import io.renren.modules.yckj.enums.status.CouponsStatus;
import io.renren.modules.yckj.enums.type.AmountType;
import io.renren.modules.yckj.service.*;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 用户表
 *
 * @author Mark sunlightcs@gmail.com
 * @since 1.0.0 2025-04-17
 */
@Service
@AllArgsConstructor
public class UserServiceImpl extends CrudServiceImpl<UserDao, UserEntity, UserDTO> implements UserService {
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
    public static final String WX_TOKEN = "https://api.weixin.qq.com/cgi-bin/token";
    public static final String WX_PHONE = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";
    private static final String WX_MSG = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
    private static final String WX_TAG_USER = "https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token=";
    private static final String WX_GET_TAG = "https://api.weixin.qq.com/cgi-bin/tags/get?access_token=";

    @Autowired
    private WeChatProperties weChatProperties;

    private final TeamRelationService teamRelationService;

    private final TeamService teamService;

    private final TokenService tokenService;

    private final CouponsLogsService couponsLogsService;


    @Override
    public QueryWrapper<UserEntity> getWrapper(Map<String, Object> params) {
        String id = (String) params.get("id");
        String key = (String) params.get("key");
        Object type = params.get("type");
        Object authentication = params.get("authentication");

        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(id), "id", id);
        wrapper.eq(ObjectUtil.isAllNotEmpty(type), "type", type);
        wrapper.eq(ObjectUtil.isAllNotEmpty(authentication), "authentication", authentication);
        wrapper.and(StrUtil.isNotBlank(key), a -> a.like("username", key).or().like("mobile", key).or().like("realname", key).or().like("company", key));
        return wrapper;
    }

    @Override
    public UserEntity getByMobile(String mobile) {
        return baseDao.getUserByMobile(mobile);
    }

    @Override
    public UserEntity getUserByUserId(Long userId) {
        Map<String, Object> params = new HashMap<>();
        params.put("userId", ThreadLocalUtil.getUserId());
        params.put("available", true);
        params.put("status", CouponsStatus.START.getCode());
        PageData<CouponsLogsDTO> page = couponsLogsService.page(params);
        UserEntity user = baseDao.getUserByUserId(userId);
        if (user != null) {
            user.setCoupons(String.valueOf(page.getTotal()));
        }
        return user;
    }

    @Override
    public Map<String, Object> login(LoginDTO dto) {

        UserEntity user = getByMobile(dto.getMobile());
        AssertUtils.isNull(user, ErrorCode.ACCOUNT_PASSWORD_ERROR);

        //密码错误
//        if (!user.getPassword().equals(DigestUtil.sha256Hex(dto.getPassword()))) {
//            throw new RenException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
//        }

        //获取登录token
        TokenEntity tokenEntity = tokenService.createToken(user.getId());

        Map<String, Object> map = new HashMap<>(2);
        map.put("token", tokenEntity.getToken());
        map.put("expire", tokenEntity.getExpireDate().getTime() - System.currentTimeMillis());

        return map;
    }


    /**
     * 根据code，获取openid,存入数据库
     * 先判断数据库有没有对应openid
     * 如果有，直接完成登录
     * 如果没有，先保存数据，再登录
     *
     * @param dto 登录表单
     * @return login info
     */
    @Override
    public Map<String, Object> wxLogin(LoginDTO dto) {
        String openId = getOpenid(dto.getCode());
        //判断openid是否为空，如果为空表示登录失败，抛出业务异常
        AssertUtils.isNull(openId, ErrorCode.WX_CODE_ERROR, ErrorCode.WX_CODE_ERROR_MSG);

        //判断当前用户是否是新用户
        UserEntity user = baseDao.getUserByOpenId(openId);
        if (user == null) {
            user = new UserEntity();
            user.setMobile(dto.getMobile());
            user.setUsername(dto.getMobile());
            user.setAvatar(dto.getAvatar());
            user.setOpenid(openId);
            user.setCreateDate(new Date());
            baseDao.insert(user);
        }

        //获取登录token
        TokenEntity tokenEntity = tokenService.createToken(user.getId());

        Map<String, Object> map = new HashMap<>(2);
        map.put("token", tokenEntity.getToken());
        map.put("expire", tokenEntity.getExpireDate().getTime() - System.currentTimeMillis());
        //用户信息
        map.put("userId", user.getId());
        map.put("mobile", user.getMobile());
        map.put("username", user.getUsername());
        map.put("avatar", user.getAvatar());
        map.put("authentication", user.getAuthentication());

        return map;
    }

    /**
     * 调用微信接口服务，获取当前微信用户的手机号
     *
     * @return 手机号
     */
    @Override
    public String getUserPhone(String code) throws Exception {
        String accessToken = getAccessToken(weChatProperties.getAppid(), weChatProperties.getSecret());
        Map<String, String> map = new HashMap<>();
        map.put("code", code);
        return HttpClientUtil.doPost4Json(WX_PHONE + "?access_token=" + accessToken, map);
    }

    @Override
    public Map<String, BigDecimal> getAvailableBalance(Long userId, Long teamId) {
        Map<String, BigDecimal> map = new HashMap<>();
        map.put("user", BigDecimal.ZERO);
        map.put("team", BigDecimal.ZERO);
        UserDTO userDTO = this.get(userId);
        if (userDTO != null) {
            BigDecimal availableBalance = userDTO.getBalance().add(userDTO.getDebtLimit()).subtract(userDTO.getDebtLimitUse());
            map.put("user", availableBalance);
        }
        if (teamId != null && teamId > 0) {
            BigDecimal availableBalance = BigDecimal.ZERO;
            TeamRelationEntity teamRelation = teamRelationService.getByTeamIdAndUserId(teamId, userId);
            if (teamRelation != null) {
                //查看当前组的最大可用余额
                TeamDTO teamDTO = teamService.get(teamId);
                BigDecimal teamMax = BigDecimal.ZERO;
                if (teamDTO != null) {
                    teamMax = teamDTO.getBalance().add(teamDTO.getDebtLimit()).subtract(teamDTO.getDebtLimitUse());
                }
                //固定金额时
                if (teamRelation.getAmountPower().equals(AmountType.FIXED.getCode())) {
                    BigDecimal fixedBalance = teamRelation.getDebtLimit().subtract(teamRelation.getDebtLimitUse());
                    availableBalance = fixedBalance.compareTo(teamMax) > 0 ? teamMax : fixedBalance;
                } else if (teamRelation.getAmountPower().equals(AmountType.ALL.getCode())) {
                    availableBalance = teamMax;
                }
            }
            map.put("team", availableBalance);
        }
        return map;
    }

    @Override
    public Map<String, BigDecimal> getBalance(Long userId, Long teamId) {
        Map<String, BigDecimal> map = new HashMap<>();
        map.put("user", BigDecimal.ZERO);
        map.put("team", BigDecimal.ZERO);
        UserDTO userDTO = this.get(userId);
        if (userDTO != null) {
            map.put("user", userDTO.getBalance());
        }
        if (teamId != null && teamId > 0) {
            TeamRelationEntity teamRelation = teamRelationService.getByTeamIdAndUserId(teamId, userId);
            if (teamRelation != null) {
                TeamDTO teamDTO = teamService.get(teamId);
                if (teamDTO != null) {
                    map.put("team", teamDTO.getBalance());
                }
            }
        }
        return map;
    }

    /**
     * 调用腾讯云接口服务，验证身份证信息
     *
     * @param name 姓名
     * @param idNo 身份证号
     * @return true: 验证通过 false: 验证失败
     */
    @Override
    public boolean idCardVerification(String name, String idNo) {
        boolean flag = false;
        Map<String, Object> map = new HashMap<>();
        try {
            // 实例化一个认证对象，入参需要传入腾讯云账户 SecretId 和 SecretKey，此处还需注意密钥对的保密
            // 代码泄露可能会导致 SecretId 和 SecretKey 泄露，并威胁账号下所有资源的安全性
            // 以下代码示例仅供参考，建议采用更安全的方式来使用密钥
            // 请参见：https://cloud.tencent.com/document/product/1278/85305
            // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取
            Credential cred = new Credential(weChatProperties.getSecretId(), weChatProperties.getSecretKey());
            // 使用临时密钥示例
            // Credential cred = new Credential("SecretId", "SecretKey", "Token");
            // 实例化一个http选项，可选的，没有特殊需求可以跳过
            HttpProfile httpProfile = new HttpProfile();
            httpProfile.setEndpoint("faceid.tencentcloudapi.com");
            // 实例化一个client选项，可选的，没有特殊需求可以跳过
            ClientProfile clientProfile = new ClientProfile();
            clientProfile.setHttpProfile(httpProfile);
            // 实例化要请求产品的client对象,clientProfile是可选的
            FaceidClient client = new FaceidClient(cred, "", clientProfile);
            // 实例化一个请求对象,每个接口都会对应一个request对象
            IdCardVerificationRequest req = new IdCardVerificationRequest();
            req.setName(name);
            req.setIdCard(idNo);
            // 返回的resp是一个IdCardVerificationResponse的实例，与请求对象对应
            IdCardVerificationResponse resp = client.IdCardVerification(req);
//            System.out.println(AbstractModel.toJsonString(resp));
            flag = resp.getResult().equals("0");
            // 输出json格式的字符串回包
        } catch (TencentCloudSDKException e) {
            System.out.println(e.toString());
        }
        return flag;
    }

    /**
     * 调用微信接口服务，获取当前微信用户的openid
     *
     * @param code code
     * @return openid
     */
    private String getOpenid(String code) {
        Map<String, String> map = new HashMap<>();
        map.put("appid", weChatProperties.getAppid());
        map.put("secret", weChatProperties.getSecret());
        map.put("js_code", code);
        map.put("grant_type", "authorization_code");
        String json = HttpClientUtil.doGet(WX_LOGIN, map);
        JSONObject jsonObject = new JSONObject(json);
        System.out.println(jsonObject.toString());
        return jsonObject.getStr("openid");
    }

    /**
     * 调用微信接口服务，获取当前微信用户的accessToken
     *
     * @return accessToken
     */
    private String getAccessToken(String appId, String secret) {
        Map<String, String> map = new HashMap<>();
        map.put("appid", appId);
        map.put("secret", secret);
        map.put("grant_type", "client_credential");
        String json = HttpClientUtil.doGet(WX_TOKEN, map);
        JSONObject jsonObject = new JSONObject(json);
        return jsonObject.getStr("access_token");
    }

    /***
     * 发送模板消息
     *  （消费成功通知）
     */
    @Override
    public String sendTemplateMsg(String openId, String machineName, String startTime, String endTime, String projectName, String phone) throws IOException {
        //获取token，获取的是公众号的token，验证通过，拿到token才能发送给关注了自己公众号的微信用户
        String token = getAccessToken(weChatProperties.getServerAppId(), weChatProperties.getServerSecret());
        //消息模板ID，步骤3中的模板的id
        String template_id = weChatProperties.getTemplateId();
        // 接口地址
        String sendMsgApi = WX_MSG + token;
        //openId微信号关注服务号的唯一标识
        String toUser = openId;
        //整体参数map
        Map<String, Object> paramMap = new HashMap<>();
        //toUser就是接收人的openID,步骤3中的微信号
        paramMap.put("touser", toUser);
        //template_id是步骤4中创建的模板的id
        paramMap.put("template_id", template_id);
        //消息主题显示相关map
        Map<String, Object> dataMap = new HashMap<>();
        //对应消息模板的{{dateTime.DATA}},第二个参数是颜色，目前测试是无效的，可以不要
        dataMap.put("thing14", createMsg(machineName));
        dataMap.put("time4", createMsg(startTime));
        dataMap.put("time5", createMsg(endTime));
        dataMap.put("thing18", createMsg(projectName));
        dataMap.put("phone_number11", createMsg(phone));
        //data是模板中的参数的map集合，键值对
        paramMap.put("data", dataMap);
        return HttpClientUtil.doPost4JsonObject(sendMsgApi, paramMap);
    }

    /**
     * 构建消息，
     *
     * @param value value
     * @return 消息内容
     */
    private Map<String, String> createMsg(String value) {
        return Map.of("value", value);
    }


    @Override
    public String getTags() throws IOException {
        String accessToken = getAccessToken(weChatProperties.getServerAppId(), weChatProperties.getServerSecret());
        // 拼接完整的请求URL
        String url = WX_GET_TAG + accessToken;
        Map<String, String> paramMap = new HashMap<>();
        String json = HttpClientUtil.doGet(url, paramMap);
        System.out.printf("json:%s", json);
        return json;
    }


    @Override
    public String getTagUsers() throws IOException {
        String accessToken = getAccessToken(weChatProperties.getServerAppId(), weChatProperties.getServerSecret());
        // 拼接完整的请求URL
        String url = WX_TAG_USER + accessToken;
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("tagid", "2");
        String json = HttpClientUtil.doPost4Json(url, paramMap);
        System.out.printf("json:%s", json);
        return json;
    }


}